module Reader where

import Result
import ResultState
import Accessor


data Error p = UnexpectedEOF
             | MissingToken
             | UnexpectedToken
             | FailedAssertion
             | UnusedInput
               deriving (Show)


type ReaderState s p = [(s, p)]

type Reader s p a = ResultState (ReaderState s p) (Error p) a



endReached :: Reader s p Bool
-----------------------------
endReached = do ss <- get state
                return $ null ss


eof :: Reader s p ()
--------------------
eof = do b <- endReached
         assert b


peek :: Reader s p s
--------------------
peek = do ss <- get state
          case ss of
            []         -> failure UnexpectedEOF
            (x, _) : _ -> return x


pop :: Reader s p s
-------------------
pop = do ss <- get state
         case ss of
           []         -> failure UnexpectedEOF
           (x, _):xs  -> do set state xs
                            return x


position :: Reader s p p
------------------------
position = do ss <- get state
              case ss of
                []         -> failure UnexpectedEOF
                (_, p) : _ -> return p
                

choice :: [Reader s p a] -> Reader s p a
----------------------------------------
choice []     = failure UnexpectedToken
choice (r:rs) = rollback r (\_ -> choice rs)


many :: Reader s p a -> Reader s p [a]
--------------------------------------
many reader = choice [ do x <- reader
                          xs <- many reader
                          return $ x : xs
                     , return []
                     ]


many1 :: Reader s p a -> Reader s p [a]
---------------------------------------
many1 reader = do xs <- many reader
                  case xs of
                    [] -> failure MissingToken
                    _  -> return xs


expect :: (s -> Bool) -> Reader s p s
-------------------------------------
expect pred = do x <- peek
                 if pred x
                 then return x
                 else failure UnexpectedToken


single :: (s -> Bool) -> Reader s p s
-------------------------------------
single pred = do x <- expect pred
                 pop
                 return x


assert :: Bool -> Reader s p ()
-------------------------------
assert True  = return ()
assert False = failure FailedAssertion


optional :: (s -> Bool) -> s -> Reader s p s
--------------------------------------------
optional pred x = do b <- endReached
                     if b
                     then return x
                     else do y <- peek
                             if pred y
                             then do pop
                                     return y
                             else return x


separatedBy :: Reader s p a -> Reader s p b -> Reader s p [a]
-------------------------------------------------------------
separatedBy reader sep = choice [ do x <- reader
                                     xs <- many (sep >> reader)
                                     return $ x : xs
                                , return []
                                ]
                                     


ignore :: Reader s p a -> Reader s p ()
---------------------------------------
ignore reader = do reader
                   return ()

                  
parse :: Reader s p a -> [(s, p)] -> Result (Error p) a
-------------------------------------------------------
parse reader input = case run reader input of
                       Success (a, _)   -> Success a
                       Failure e        -> Failure e
